// TMake 主入口文件
// 提供编译器核心功能和命令行工具

import { TMakeLexer } from './lexer';
import { TMakeParser } from './parser';
import { TMakeCompiler } from './compiler';
import { parseArgs } from './build';
import { CompileResult, CompilerError } from './types';
import { createPluginManager, PluginSystem, PluginLifecycleEvent } from './plugin-system';
import * as fs from 'fs';
import * as path from 'path';
import * as crypto from 'crypto';
import tieBuildPlugin from './plugins/tie-build-plugin';
import advancedBuildPlugin from './plugins/advanced-build-plugin';

// 任务函数类型定义
type TaskFunction = () => Promise<void> | void;

/**
 * 计算文件的SHA-256哈希值
 * @param filePath 文件路径
 * @returns 文件的哈希值
 */
async function getFileHash(filePath: string): Promise<string> {
  return new Promise((resolve, reject) => {
    try {
      const hash = crypto.createHash('sha256');
      const stream = fs.createReadStream(filePath);

      stream.on('error', (error) => {
        stream.destroy();
        reject(error);
      });

      stream.on('data', (chunk) => {
        hash.update(chunk);
      });

      stream.on('end', () => {
        const fileHash = hash.digest('hex');
        resolve(fileHash);
      });
    } catch (error) {
      reject(error);
    }
  });
}

/**
 * 计算目录中所有源文件的哈希值
 * @param dirPath 目录路径
 * @param extensions 需要计算哈希的文件扩展名数组
 * @returns 文件路径到哈希值的映射
 */
async function getDirectoryFilesHash(dirPath: string, extensions: string[]): Promise<Map<string, string>> {
  const hashMap = new Map<string, string>();
  const projectDir = process.cwd();

  async function processDir(currentPath: string) {
    try {
      const entries = fs.readdirSync(currentPath);

      for (const entry of entries) {
        const fullPath = path.join(currentPath, entry);
        const stats = fs.statSync(fullPath);

        if (stats.isDirectory()) {
          await processDir(fullPath);
        } else if (extensions.some(ext => entry.endsWith(ext))) {
          try {
            const hash = await getFileHash(fullPath);
            hashMap.set(fullPath, hash);
          } catch (error) {
            console.warn(`无法计算文件哈希: ${fullPath}`, error);
          }
        }
      }
    } catch (error) {
      console.warn(`无法访问目录: ${currentPath}`, error);
    }
  }

  await processDir(dirPath);
  return hashMap;
}

/**
 * 缓存元数据接口
 */
interface CacheMetadata {
  timestamp: number;
  sourceFileHashes: Record<string, string>; // 源代码文件哈希
  packageFileHashes: Record<string, string>; // 绳包文件哈希
  outputSrcHashes: Record<string, string>; // 输出目录src文件哈希
  tmakeHashes: Record<string, string>; // tmake文件哈希
}

/**
 * 保存缓存元数据到文件
 * @param cachePath 缓存文件路径
 * @param metadata 缓存元数据
 */
function saveCacheMetadata(cachePath: string, metadata: CacheMetadata): void {
  try {
    const dir = path.dirname(cachePath);
    if (!fs.existsSync(dir)) {
      fs.mkdirSync(dir, { recursive: true });
    }
    fs.writeFileSync(cachePath, JSON.stringify(metadata, null, 2));
  } catch (error) {
    console.warn(`保存缓存元数据失败: ${error}`);
  }
}

/**
 * 从文件加载缓存元数据
 * @param cachePath 缓存文件路径
 * @returns 缓存元数据或null
 */
function loadCacheMetadata(cachePath: string): CacheMetadata | null {
  try {
    if (!fs.existsSync(cachePath)) {
      return null;
    }
    const content = fs.readFileSync(cachePath, 'utf-8');
    return JSON.parse(content) as CacheMetadata;
  } catch (error) {
    console.warn(`加载缓存元数据失败: ${error}`);
    return null;
  }
}

/**
 * 比较两个哈希映射是否相等
 * @param map1 第一个哈希映射
 * @param map2 第二个哈希映射
 * @returns 是否相等
 */
function areHashMapsEqual(map1: Map<string, string>, map2: Record<string, string>): boolean {
  // 检查键的数量是否相同
  if (map1.size !== Object.keys(map2).length) {
    return false;
  }
  const normalizedMap2: Record<string, string> = {};
  const projectDir = process.cwd();

  for (const [key, value] of Object.entries(map2)) {
    try {
      let normalizedKey: string;
      if (path.isAbsolute(key)) {
        normalizedKey = path.normalize(key);
      } else {
        normalizedKey = path.normalize(path.join(projectDir, key));
      }
      normalizedMap2[normalizedKey] = value;
    } catch (error) {
      normalizedMap2[key] = value;
    }
  }
  for (const [key, value] of map1) {
    const normalizedKey = path.normalize(key);

    // 首先尝试直接匹配标准化后的键
    if (normalizedMap2[normalizedKey] === value) {
      continue;
    }

    // 如果直接匹配失败，尝试查找是否有对应的相对路径键
    let foundMatch = false;
    for (const [map2Key, map2Value] of Object.entries(map2)) {
      if (map2Value === value) {
        // 如果哈希值匹配，检查是否是相同的文件
        try {
          let map2AbsoluteKey: string;
          if (!path.isAbsolute(map2Key)) {
            map2AbsoluteKey = path.normalize(path.join(projectDir, map2Key));
            if (map2AbsoluteKey === normalizedKey) {
              foundMatch = true;
              break;
            }
          }
        } catch (error) {
          // 忽略错误，继续查找
        }
      }
    }

    if (!foundMatch) {
      return false;
    }
  }

  return true;
}

/**
 * 校验outputSrcHashes中文件哈希与实际文件哈希一致性
 * @param cachedMetadata 缓存元数据
 * @param outputDir 输出目录
 * @returns 是否一致
 */
async function validateOutputSrcHashes(cachedMetadata: CacheMetadata, outputDir: string): Promise<boolean> {
  try {
    const outputSrcDir = path.join(outputDir, 'src');
    
    // 如果缓存中的outputSrcHashes为空，认为校验通过
    if (!cachedMetadata.outputSrcHashes || Object.keys(cachedMetadata.outputSrcHashes).length === 0) {
      return true;
    }

    // 检查outputSrcDir是否存在
    if (!fs.existsSync(outputSrcDir)) {
      console.warn('输出目录不存在，缓存校验失败');
      return false;
    }

    // 校验每个缓存的文件哈希
    for (const [relativePath, cachedHash] of Object.entries(cachedMetadata.outputSrcHashes)) {
      // 构建完整文件路径，处理可能的绝对路径问题
      let filePath;
      if (path.isAbsolute(relativePath)) {
        // 如果是绝对路径，直接使用
        filePath = relativePath;
      } else {
        // 如果是相对路径，相对于outputSrcDir
        filePath = path.join(outputSrcDir, relativePath);
      }
      
      // 检查文件是否存在
      if (!fs.existsSync(filePath)) {
        console.warn(`缓存中的文件不存在: ${filePath}`);
        return false;
      }
      
      // 计算实际文件哈希
      const actualHash = await getFileHash(filePath);
      
      // 比较哈希值
      if (actualHash !== cachedHash) {
        console.warn(`文件哈希不匹配: ${filePath}`);
        return false;
      }
    }
    
    return true;
  } catch (error) {
    console.warn(`校验outputSrcHashes时出错: ${error}`);
    return false;
  }
}

// 任务接口定义
interface Task {
  name: string;           // 任务名称
  description: string;    // 任务描述
  action: TaskFunction;   // 任务执行函数
}

// 任务注册表类
class TaskRegistry {
  private tasks: Map<string, Task> = new Map();      // 任务存储映射
  private defaultTask: string | null = null;         // 默认任务名称

  // 注册新任务
  register(task: Task): void {
    this.tasks.set(task.name, task);
    // 如果是第一个注册的任务，自动设为默认任务
    if (this.tasks.size === 1) {
      this.defaultTask = task.name;
    }
  }

  // 设置默认任务
  setDefaultTask(name: string): void {
    if (this.tasks.has(name)) {
      this.defaultTask = name;
    }
  }

  // 根据名称获取任务
  getTask(name: string): Task | undefined {
    return this.tasks.get(name);
  }

  // 获取默认任务名称
  getDefaultTask(): string | null {
    return this.defaultTask;
  }

  // 获取所有注册的任务
  getAllTasks(): Task[] {
    return Array.from(this.tasks.values());
  }

  // 检查是否存在指定名称的任务
  hasTask(name: string): boolean {
    return this.tasks.has(name);
  }
}
// 创建任务注册表实例
const taskRegistry = new TaskRegistry();

/**
 * 加载本地扩展（向后兼容）
 * @param compiler TMake编译器实例
 */
function loadLocalExtensions(compiler: TMakeCompiler): void {
  // 检查是否存在源代码目录或编译配置文件
  const hasSourceFolder = fs.existsSync(path.join(process.cwd(), '源代码'));
  const hasConfigFile = fs.existsSync(path.join(process.cwd(), '编译配置.tmake'));

  // 确定.tmakes目录路径
  const tmakesDir = (hasSourceFolder || hasConfigFile)
    ? path.join(process.cwd(), '.tmakes')
    : path.join(process.cwd(), '.tmakes');

  // 尝试加载.tmakes目录中的插件
  if (fs.existsSync(tmakesDir)) {
    try {
      const pluginSystem = createPluginManager(compiler);
      pluginSystem.loadPluginsFromDirectory(tmakesDir);
      // 移除调试日志
    } catch (error: any) {
      console.error(`读取插件目录失败: ${error.message}`);
    }
  }
}

/**
 * TMake 到 JSON 的编译器类
 * 提供将 TMake 脚本编译为 JSON 配置的功能
 */
export class TMakeToJSONCompiler {
  private compiler: TMakeCompiler;      // TMake编译器实例
  private pluginSystem: PluginSystem;   // 插件系统实例

  /**
   * 构造函数
   * 初始化编译器和插件系统
   */
  constructor() {
    // 创建编译器实例
    this.compiler = new TMakeCompiler();

    // 初始化插件系统
    this.pluginSystem = createPluginManager(this.compiler);

    // 加载核心插件
    this.pluginSystem.loadPlugin(tieBuildPlugin);
    this.pluginSystem.loadPlugin(advancedBuildPlugin);
    const pluginsDir = path.join(__dirname, 'plugins');
    if (fs.existsSync(pluginsDir)) {
      this.pluginSystem.loadPluginsFromDirectory(pluginsDir);
    }


    this.pluginSystem.emitEvent(PluginLifecycleEvent.BEFORE_INIT);
    this.pluginSystem.emitEvent(PluginLifecycleEvent.AFTER_INIT);


    loadLocalExtensions(this.compiler);
  }

  private registerDefaultExtensions(): void {


    // 移除调试日志
  }

  loadCustomExtensions(extensionsDir: string): void {

    console.warn('loadCustomExtensions 已弃用，请使用新的插件系统');
    if (fs.existsSync(extensionsDir)) {
      try {
        this.pluginSystem.loadPluginsFromDirectory(extensionsDir);
      } catch (error: any) {
        console.error(`读取插件目录失败: ${error.message}`);
      }
    } else {
      console.warn(`插件目录不存在: ${extensionsDir}`);
    }
  }

  compile(source: string): CompileResult {

    this.pluginSystem.emitEvent(PluginLifecycleEvent.BEFORE_COMPILE, source);

    const errors: any[] = [];
    const warnings: string[] = [];

    try {
      const lexer = new TMakeLexer(source);
      const { tokens, errors: lexerErrors } = lexer.tokenize();
      errors.push(...lexerErrors);

      if (lexerErrors.length > 0) {
        return {
          success: false,
          errors: lexerErrors,
          warnings
        };
      }

      const parser = new TMakeParser(tokens);
      const { ast, errors: parserErrors } = parser.parse();
      errors.push(...parserErrors);

      if (parserErrors.length > 0) {
        return {
          success: false,
          errors: parserErrors,
          warnings,
          ast
        };
      }

      const { config, errors: compilerErrors, warnings: compilerWarnings } = this.compiler.compile(ast);
      errors.push(...compilerErrors);
      warnings.push(...compilerWarnings);

      const jsonConfig = JSON.stringify(config, null, 2);

      const result = {
        success: errors.length === 0,
        jsonConfig: errors.length === 0 ? jsonConfig : undefined,
        errors,
        warnings,
        ast
      };


      this.pluginSystem.emitEvent(PluginLifecycleEvent.AFTER_COMPILE, result.success);

      return result;
    } catch (error: any) {
      const errorObj: CompilerError = {
        type: 'runtime',
        message: '编译过程发生致命错误',
        details: error.message,
        line: 0,
        column: 0
      };
      errors.push(errorObj);


      this.pluginSystem.emitEvent(PluginLifecycleEvent.ON_ERROR, errorObj);

      return {
        success: false,
        errors,
        warnings
      };
    }
  }

  compileFile(filePath: string): CompileResult {
    try {
      if (!fs.existsSync(filePath)) {
        const error: CompilerError = {
          type: 'runtime',
          message: `文件不存在: ${filePath}`,
          line: 0,
          column: 0
        };


        this.pluginSystem.emitEvent(PluginLifecycleEvent.ON_ERROR, error);

        return {
          success: false,
          errors: [error],
          warnings: []
        };
      }

      const source = fs.readFileSync(filePath, 'utf-8');
      return this.compile(source);
    } catch (error: any) {
      const errorObj: CompilerError = {
        type: 'runtime',
        message: `读取文件失败: ${filePath}`,
        details: error.message,
        line: 0,
        column: 0
      };


      this.pluginSystem.emitEvent(PluginLifecycleEvent.ON_ERROR, errorObj);

      return {
        success: false,
        errors: [errorObj],
        warnings: []
      };
    }
  }

  formatErrors(errors: any[]): string {
    return errors.map(error => {
      const location = error.line ? ` (${error.line}:${error.column})` : '';
      const token = error.token ? ` 附近 token: '${error.token}'` : '';
      const details = error.details ? `\n    详情: ${error.details}` : '';
      return `${error.type}错误${location}: ${error.message}${token}${details}`;
    }).join('\n');
  }

  formatWarnings(warnings: string[]): string {
    return warnings.map(warning => `警告: ${warning}`).join('\n');
  }
}

async function createProjectTask(): Promise<void> {
  const args = process.argv.slice(3);
  const projectName = args[0] || 'project';
  try {
    const appDir = path.dirname(process.execPath);
    const projectDir = path.join(process.cwd(), projectName);
    const tmakesDir = path.join(projectDir, '.tmakes');
    const templateDir = path.join(appDir, 'project');
    if (!fs.existsSync(projectDir)) {
      fs.mkdirSync(projectDir, { recursive: true });
    }
    if (fs.existsSync(templateDir)) {
      function copyDir(source: string, target: string) {
        if (!fs.existsSync(target)) {
          fs.mkdirSync(target, { recursive: true });
        }
        const files = fs.readdirSync(source);

        for (const file of files) {
          const sourcePath = path.join(source, file);
          const targetPath = path.join(target, file);
          if (fs.statSync(sourcePath).isDirectory()) {
            copyDir(sourcePath, targetPath);
          } else {
            if (!fs.existsSync(targetPath)) {
              fs.copyFileSync(sourcePath, targetPath);
            } else {
              // 移除调试日志
            }
          }
        }
      }
      copyDir(templateDir, projectDir);
    } else {
      // 移除调试日志
      const projectStructure = [
        path.join(projectDir, '源代码/'),
        path.join(projectDir, '绳包/'),
        tmakesDir + "/"
      ];


      for (const pathItem of projectStructure) {
        if (pathItem.endsWith('/')) {
          if (!fs.existsSync(pathItem)) {
            fs.mkdirSync(pathItem, { recursive: true });
            // 移除调试日志
          }
        }
      }
      const mainTmakePath = path.join(projectDir, '编译配置.tmake');
      if (!fs.existsSync(mainTmakePath)) {
        const templateContent = `TMake版本("1.0.0")
结绳编译器版本("4.6")
设置变量("项目名称", "${projectName}")
设置变量("版本号", "1.0.0")
设置变量("输出目录", "./dist")
设置输出文件("测试程序.exe")
设置优化级别(2)
设置日志级别("warning")
如果 平台为Windows()
    设置编译器("cl.exe")
    链接动态库("libc++.lib")
结束 如果

编译程序(读取源文件列表("./"), 输出文件)
发布模式()`;
        fs.writeFileSync(mainTmakePath, templateContent);
        // 移除调试日志
      }
    }

    // 移除调试日志
  } catch (error: any) {
    console.error(`创建项目失败: ${error.message}`);
    process.exit(1);
  }
}


async function createPluginTask(): Promise<void> {
  const args = process.argv.slice(3);
  const pluginName = args[0] || 'my-plugin';

  // 移除调试日志

  try {
    // 使用新的插件系统目录结构
    const pluginsDir = path.join(process.cwd(), 'plugins');
    if (!fs.existsSync(pluginsDir)) {
      fs.mkdirSync(pluginsDir, { recursive: true });
    }

    const pluginPath = path.join(pluginsDir, `${pluginName}.js`);

    if (fs.existsSync(pluginPath)) {
      console.error(`错误: 插件文件已存在: ${pluginPath}`);
      process.exit(1);
    }

    // 新的插件模板格式 - 修复嵌套模板字符串问题
    const pluginContent = [
      '/**',
      ' * ' + pluginName + ' 插件',
      ' * 功能描述：TMake自定义插件',
      ' */',
      '',
      'module.exports = {',
      '  // 插件元数据',
      '  metadata: {',
      '    name: \'' + pluginName + '\',',
      '    version: \'1.0.0\',',
      '    description: \'自定义TMake插件\',',
      '    author: \'Your Name\',',
      '    // 可选的依赖插件列表',
      '    dependencies: [],',
      '    // 插件配置项',
      '    config: {',
      '      enabled: true,',
      '      debug: false',
      '    }',
      '  },',
      '  ',
      '  // 初始化函数',
      '  init(api) {',
      '    // 移除调试日志',
      '    ',
      '    // 注册自定义函数',
      '    api.registerFunction(\'' + pluginName + '_func\', (node, context) => {',
      '      // 获取节点参数',
      '      const param = node.params && node.params.length > 0 ',
      '        ? api.compiler.evaluateExpression(node.params[0], context) ',
      '        : null;',
      '      ',
      '      // 实现函数逻辑',
      '      // 移除调试日志',
      '      return param || \'来自' + pluginName + '的结果\';',
      '    });',
      '    ',
      '    // 获取插件配置',
      '    const config = api.getConfig();',
      '    if (config.debug) {',
      '      // 移除调试日志',
      '    }',
      '  },',
      '  ',
      '  // 编译前钩子',
      '  [PluginLifecycleEvent.BEFORE_COMPILE](api, sourceCode) {',
      '    // 移除调试日志',
      '  },',
      '  ',
      '  // 解析后钩子 - 可用于AST操作',
      '  [PluginLifecycleEvent.AFTER_PARSE](api, ast) {',
      '    // 使用AST操作工具',
      '    const { createNode, findAllNodes } = api.ast;',
      '    ',
      '    // 查找特定类型的节点示例',
      '    const functionNodes = findAllNodes(ast, node => node.type === \'function\');',
      '    // 移除调试日志',
      '  },',
      '  ',
      '  // 构建前钩子',
      '  [PluginLifecycleEvent.BEFORE_BUILD](api, options) {',
      '    // 移除调试日志',
      '  },',
      '  ',
      '  // 错误处理钩子',
      '  [PluginLifecycleEvent.ON_ERROR](api, error) {',
      '    // 移除调试日志',
      '  }',
      '};'
    ].join('\n');

    fs.writeFileSync(pluginPath, pluginContent);
    // 移除调试日志
  } catch (error: any) {
    console.error(`创建插件失败: ${error.message}`);
    process.exit(1);
  }
}


async function precompileTask(): Promise<void> {
  try {
    const projectDir = process.cwd();
    const cacheDir = path.join(process.cwd(), '.cache');
    if (!fs.existsSync(cacheDir)) {
      fs.mkdirSync(cacheDir, { recursive: true });
    }
    const tmakeFiles: string[] = [];
    function findTmakeFiles(dir: string) {
      const files = fs.readdirSync(dir);
      for (const file of files) {
        const fullPath = path.join(dir, file);
        if (fs.statSync(fullPath).isDirectory()) {
          findTmakeFiles(fullPath);
        } else if (file.endsWith('.tmake')) {
          tmakeFiles.push(fullPath);
        }
      }
    }
    findTmakeFiles(projectDir);
    if (tmakeFiles.length === 0) {
      // 移除调试日志
      return;
    }

    // 移除调试日志
    const compiler = new TMakeToJSONCompiler();
    const cacheFilePath = path.join(cacheDir, 'compiler-config.json');
    const configTmakeFile = tmakeFiles.find(file => path.basename(file) === '编译配置.tmake');
    if (configTmakeFile) {
      const result = compiler.compileFile(configTmakeFile);
      if (result.success) {
        if (result.jsonConfig) {
          fs.writeFileSync(cacheFilePath, result.jsonConfig);
        }
        if (result.warnings.length > 0) {
          debugLog(compiler.formatWarnings(result.warnings));
        }
      } else {
        console.error(`    ✗ 编译失败:`);
        console.error(compiler.formatErrors(result.errors));
      }
    } else if (tmakeFiles.length > 0) {
      const result = compiler.compileFile(tmakeFiles[0]);
      if (result.success) {
        if (result.jsonConfig) {
          fs.writeFileSync(cacheFilePath, result.jsonConfig);
        }
        if (result.warnings.length > 0) {
          debugLog(compiler.formatWarnings(result.warnings));
        }
      } else {
        console.error(`    ✗ 编译失败:`);
        console.error(compiler.formatErrors(result.errors));
      }
    }

    // 移除调试日志
  } catch (error: any) {
    console.error(`预编译失败: ${error.message}`);
    process.exit(1);
  }
}


// 调试输出辅助函数
function debugLog(message: string, options?: {debug?: boolean}) {
  if (options?.debug) {
    console.log(`调试信息: ${message}`);
  }
}

async function compileTask(): Promise<void> {
  console.log('开始编译项目...');

  try {
    const projectDir = process.cwd();
    if (!fs.existsSync(path.join(projectDir, '源代码')) || !fs.existsSync(path.join(projectDir, '编译配置.tmake'))) {
      console.error('错误: 当前目录不是有效的结绳项目，请确保在项目目录内运行');
      process.exit(1);
    }

    const configFilePath = path.join(projectDir, '编译配置.tmake');
    const jsonConfigPath = path.join(projectDir, '.cache', 'compiler-config.json');
    const cacheMetadataPath = path.join(projectDir, '.cache', 'cache-metadata.json');

    // 获取源代码目录的路径
    const sourceCodeDir = path.join(projectDir, '源代码');

    // 初始设置为缓存无效
    let isCacheValid = false;

    try {
      // 检查缓存文件和元数据文件是否存在
      if (fs.existsSync(jsonConfigPath) && fs.existsSync(cacheMetadataPath)) {
        // 加载缓存元数据
        const cachedMetadata = loadCacheMetadata(cacheMetadataPath);

        if (cachedMetadata) {
          // 计算当前源代码文件的哈希值
          const currentSourceHashes = await getDirectoryFilesHash(sourceCodeDir, ['.t']);

          // 计算绳包目录的哈希值
          const packageDir = path.join(projectDir, '绳包');
          const currentPackageHashes = fs.existsSync(packageDir)
            ? await getDirectoryFilesHash(packageDir, ['.t', '.tmake', '.cpp', '.h', '.c', '.hpp'])
            : new Map();

          // 计算tmake文件的哈希值
          const tmakeFiles = await getDirectoryFilesHash(projectDir, ['.tmake']);

          // 检查缓存是否完全有效（所有部分都匹配）
          const isSourceValid = areHashMapsEqual(currentSourceHashes, cachedMetadata.sourceFileHashes);
          const isPackageValid = areHashMapsEqual(currentPackageHashes, cachedMetadata.packageFileHashes);
          const isTmakeValid = areHashMapsEqual(tmakeFiles, cachedMetadata.tmakeHashes);

          // 总缓存有效性（基于tmake文件和源代码/绳包）
          isCacheValid = isSourceValid && isPackageValid && isTmakeValid;
        }
      }
    } catch (error) {
      console.warn(`检查缓存有效性时出错: ${error}`);
      // 出错时认为缓存无效
      isCacheValid = false;
    }

    // 重新获取必要的哈希值用于细化缓存逻辑
    const configContent = fs.readFileSync(configFilePath, 'utf-8');
    const tmakeFiles = await getDirectoryFilesHash(projectDir, ['.tmake']);
    const currentSourceHashes = await getDirectoryFilesHash(sourceCodeDir, ['.t']);
    const packageDir = path.join(projectDir, '绳包');
    const currentPackageHashes = fs.existsSync(packageDir)
      ? await getDirectoryFilesHash(packageDir, ['.t', '.tmake', '.cpp', '.h', '.c', '.hpp'])
      : new Map();

    let needsConfigRecompile = !isCacheValid;
    let cachedMetadata: CacheMetadata | null = null;

    // 重新加载缓存元数据
    if (fs.existsSync(cacheMetadataPath)) {
      cachedMetadata = loadCacheMetadata(cacheMetadataPath);
    }

    // 检查是否只需要重新编译配置文件
    if (!needsConfigRecompile && cachedMetadata) {
      const isTmakeChanged = !areHashMapsEqual(tmakeFiles, cachedMetadata.tmakeHashes);

      // 只有当tmake文件变化时才需要重新编译配置文件
      if (isTmakeChanged) {
        console.log('检测到.tmake文件有变化，将重新编译配置文件...');
        needsConfigRecompile = true;
      }
    }

    if (needsConfigRecompile) {
      const jsonCompiler = new TMakeToJSONCompiler();
      const compileResult = jsonCompiler.compile(configContent);

      if (!compileResult.success) {
        console.error('配置文件编译失败:');
        console.error(jsonCompiler.formatErrors(compileResult.errors));
        process.exit(1);
      }

      if (compileResult.jsonConfig) {
        // 确保缓存目录存在
        if (!fs.existsSync(path.dirname(jsonConfigPath))) {
          fs.mkdirSync(path.dirname(jsonConfigPath), { recursive: true });
        }

        // 保存编译结果
        fs.writeFileSync(jsonConfigPath, compileResult.jsonConfig, 'utf-8');

        try {
          // 计算源代码文件的哈希值
          const sourceHashes = await getDirectoryFilesHash(sourceCodeDir, ['.t']);

          // 计算绳包目录的哈希值
          const packageDir = path.join(projectDir, '绳包');
          const packageHashes = fs.existsSync(packageDir)
            ? await getDirectoryFilesHash(packageDir, ['.t', '.tmake', '.cpp', '.h', '.c', '.hpp'])
            : new Map();

          // 计算tmake文件的哈希值
          const tmakeHashes = await getDirectoryFilesHash(projectDir, ['.tmake']);
          const outputDir = './dist';
          const outputSrcDir = path.join(outputDir, 'src');
          const outputSrcHashes = fs.existsSync(outputSrcDir)
            ? await getDirectoryFilesHash(outputSrcDir, ['.cpp', '.h', '.c', '.hpp'])
            : new Map();

          // 转换Maps为对象以便JSON序列化
          const sourceHashesObject: Record<string, string> = {};
          sourceHashes.forEach((hash, filePath) => {
            sourceHashesObject[filePath] = hash;
          });

          const packageHashesObject: Record<string, string> = {};
          packageHashes.forEach((hash, filePath) => {
            packageHashesObject[filePath] = hash;
          });

          const tmakeHashesObject: Record<string, string> = {};
          tmakeHashes.forEach((hash, filePath) => {
            tmakeHashesObject[filePath] = hash;
          });

          const outputSrcHashesObject: Record<string, string> = {};
          outputSrcHashes.forEach((hash, filePath) => {
            outputSrcHashesObject[filePath] = hash;
          });

          // 创建并保存缓存元数据
          const cacheMetadata: CacheMetadata = {
            timestamp: Date.now(),
            sourceFileHashes: sourceHashesObject,
            packageFileHashes: packageHashesObject,
            tmakeHashes: tmakeHashesObject,
            outputSrcHashes: outputSrcHashesObject
          };

          saveCacheMetadata(cacheMetadataPath, cacheMetadata);
        } catch (error) {
          console.warn(`生成缓存元数据失败: ${error}`);
        }
      }
    }
    const tFiles: string[] = [];

    function findTFiles(dir: string) {
      const files = fs.readdirSync(dir);
      for (const file of files) {

        if (typeof file === 'string' && file) {
          const fullPath = path.join(dir, file);
          try {
            if (fs.statSync(fullPath).isDirectory()) {
              findTFiles(fullPath);
            } else if (file.endsWith('.t')) {
              tFiles.push(fullPath);
            }
          } catch (err) {
            console.warn(`无法访问文件或目录: ${fullPath}, 跳过`);
          }
        }
      }
    }

    findTFiles(projectDir);

    if (tFiles.length === 0) {
      console.warn('警告: 未找到结绳源代码文件(.t)');
    }

    // 移除调试日志


    const args = process.argv.slice(3);
    const { files: buildFiles, options } = parseArgs(args);


    const sourceFiles = buildFiles.length > 0 ? buildFiles : tFiles;


    // 获取JSON配置
    let configFromJson = null;
    try {
      if (fs.existsSync(jsonConfigPath)) {
        const configJsonContent = fs.readFileSync(jsonConfigPath, 'utf-8');
        configFromJson = JSON.parse(configJsonContent);
        // 移除了非必要的日志输出
      }
    } catch (error: any) {
      // 保留警告信息
      console.warn(`读取JSON配置文件时出错: ${error.message}`);
    }

    // 检查是否可以跳过结绳编译直接编译cpp
    let skipTieCompile = false;

    // 只有当outputSrcDir实际存在且包含文件时，才考虑跳过tie编译
    const outputDir = process.cwd() + '/dist';
    const outputSrcDir = path.join(outputDir, 'src');

    debugLog('开始检查skipTieCompile条件', {debug: options.debug});
    debugLog(`outputSrcDir存在? ${fs.existsSync(outputSrcDir)}`, {debug: options.debug});
    debugLog(`缓存文件存在? ${fs.existsSync(cacheMetadataPath)}`, {debug: options.debug});

    if (fs.existsSync(outputSrcDir) && fs.existsSync(cacheMetadataPath)) {
      const cachedMetadata = loadCacheMetadata(cacheMetadataPath);
      if (cachedMetadata) {
        debugLog('缓存元数据有效', {debug: options.debug});
        // 重新验证必要的哈希值
        const currentSourceHashes = await getDirectoryFilesHash(sourceCodeDir, ['.t']);
        const packageDir = path.join(projectDir, '绳包');
        const currentPackageHashes = fs.existsSync(packageDir)
          ? await getDirectoryFilesHash(packageDir, ['.t', '.tmake', '.cpp', '.h', '.c', '.hpp'])
          : new Map();
        const tmakeFiles = await getDirectoryFilesHash(projectDir, ['.tmake']);

        // 检查源代码、绳包和.tmake文件的哈希是否一致
        const isSourceValid = areHashMapsEqual(currentSourceHashes, cachedMetadata.sourceFileHashes);
        const isPackageValid = areHashMapsEqual(currentPackageHashes, cachedMetadata.packageFileHashes);
        const isTmakeValid = areHashMapsEqual(tmakeFiles, cachedMetadata.tmakeHashes);
        
        // 新增：校验outputSrcHashes中文件哈希与实际文件哈希一致性
        const isOutputSrcValid = await validateOutputSrcHashes(cachedMetadata, outputDir);

        debugLog(`哈希验证结果 - source:${isSourceValid}, package:${isPackageValid}, tmake:${isTmakeValid}, outputSrc:${isOutputSrcValid}`, {debug: options.debug});
        // 设置跳过标志，只有当所有哈希都一致且dist/src存在才跳过结绳编译
        skipTieCompile = isSourceValid && isPackageValid && isTmakeValid && isOutputSrcValid;

        if (skipTieCompile) {
          debugLog('检测到源代码、绳包、.tmake文件和输出文件无变化，将直接编译cpp文件...', {debug: options.debug});
        } else if (isSourceValid && isPackageValid && isTmakeValid && !isOutputSrcValid) {
          debugLog('检测到输出文件哈希不匹配，需要重新编译...', {debug: options.debug});
        }
      }
    }

    const compiler = new TMakeCompiler();
    const pluginManager = createPluginManager(compiler);

    pluginManager.loadPlugin(tieBuildPlugin);

    const fullOptions = {
      output: options.output || (configFromJson?.variables?.['输出目录'] || './dist'),
      package: options.package || 'main',
      outputFile: configFromJson?.outputFile,
      debug: options.debug !== undefined ? options.debug : !(configFromJson?.mode === 'release'),
      release: options.release !== undefined ? options.release : (configFromJson?.mode === 'release'),
      hardMode: options.hardMode !== undefined ? options.hardMode : false,
      optimize: options.optimize !== undefined ? options.optimize : (configFromJson?.optimizeLevel || 1),
      logLevel: options.logLevel || (configFromJson?.logLevel || 'info'),
      platform: options.platform || (configFromJson?.platformTarget || 'windows'),
      tieccDir: options.tieccDir || process.env.TIECC_DIR || path.join(process.cwd(), 'tiecc'),
      disableLint: options.disableLint || [],
      customArgs: options.customArgs || [],
      compilerType: options.compilerType || (configFromJson?.compiler || undefined),
      config: configFromJson || {},
      skipTieCompile: skipTieCompile
    };

    // 仅在非静默模式或调试模式下输出构建选项
    if (!options.silent && options.debug) {
      debugLog('构建选项:', {debug: fullOptions.debug});
      debugLog(`输出目录: ${fullOptions.output}`, {debug: fullOptions.debug});
      debugLog(`包名: ${fullOptions.package}`, {debug: fullOptions.debug});
      debugLog(`输出文件: ${fullOptions.outputFile}`, {debug: fullOptions.debug});
      debugLog(`调试模式: ${fullOptions.debug}`, {debug: fullOptions.debug});
      debugLog(`优化级别: ${fullOptions.optimize}`, {debug: fullOptions.debug});
      debugLog(`日志级别: ${fullOptions.logLevel}`, {debug: fullOptions.debug});
      debugLog(`平台: ${fullOptions.platform}`, {debug: fullOptions.debug});
      debugLog(`结绳编译器目录: ${fullOptions.tieccDir}`, {debug: fullOptions.debug});
    }


    let success = false;
    const targetName = 'tie';

    try {
      const pluginAPI = pluginManager['createPluginAPI']({ metadata: { name: 'compile-task' } } as any);

      debugLog(`最终skipTieCompile值为 ${fullOptions.skipTieCompile}`, {debug: fullOptions.debug});

      // 如果设置了skipTieCompile标志，直接构建cpp而不重新编译结绳代码
      if (fullOptions.skipTieCompile) {
        // 直接使用tie构建目标，但传入skipTieCompile标志，让插件内部处理
        debugLog('检测到源代码、绳包和.tmake文件无变化，将直接编译cpp文件...', {debug: fullOptions.debug});
        success = await pluginAPI.executeBuildTarget(targetName, sourceFiles, {
          ...fullOptions,
          skipTieCompile: true
        });
      } else {
        // 正常执行结绳编译
        success = await pluginAPI.executeBuildTarget(targetName, sourceFiles, fullOptions);
      }
      if (success) {
        try {
          const outputDir = path.resolve(fullOptions.output || process.cwd() + '/dist');
          const outputSrcDir = path.join(outputDir, 'src');

          // 重新计算所有哈希值
          const sourceHashes = await getDirectoryFilesHash(sourceCodeDir, ['.t']);
          const packageDir = path.join(projectDir, '绳包');
          const packageHashes = fs.existsSync(packageDir)
            ? await getDirectoryFilesHash(packageDir, ['.t', '.tmake', '.cpp', '.h', '.c', '.hpp'])
            : new Map();
          const tmakeHashes = await getDirectoryFilesHash(projectDir, ['.tmake']);
          const outputSrcHashes = fs.existsSync(outputSrcDir)
            ? await getDirectoryFilesHash(outputSrcDir, ['.cpp', '.h', '.c', '.hpp'])
            : new Map();

          // 转换Maps为对象以便JSON序列化
          const sourceHashesObject: Record<string, string> = {};
          sourceHashes.forEach((hash, filePath) => {
            sourceHashesObject[filePath] = hash;
          });

          const packageHashesObject: Record<string, string> = {};
          packageHashes.forEach((hash, filePath) => {
            packageHashesObject[filePath] = hash;
          });

          const tmakeHashesObject: Record<string, string> = {};
          tmakeHashes.forEach((hash, filePath) => {
            tmakeHashesObject[filePath] = hash;
          });

          const outputSrcHashesObject: Record<string, string> = {};
          outputSrcHashes.forEach((hash, filePath) => {
            outputSrcHashesObject[filePath] = hash;
          });

          // 创建并保存缓存元数据
          const cacheMetadata: CacheMetadata = {
            timestamp: Date.now(),
            sourceFileHashes: sourceHashesObject,
            packageFileHashes: packageHashesObject,
            tmakeHashes: tmakeHashesObject,
            outputSrcHashes: outputSrcHashesObject
          };

          saveCacheMetadata(cacheMetadataPath, cacheMetadata);
        } catch (error) {
          console.warn(`更新缓存元数据失败: ${error}`);
        }
      }
    } catch (error: any) {
      console.error(`执行构建目标失败: ${error.message}`);
      success = false;
    }

    if (success) {
      // 保留成功消息，但添加条件控制
      if (!options.silent) {
        // 移除调试日志
      }
    } else {
      // 保留错误信息
      console.error('\n编译失败！');
      process.exit(1);
    }
  } catch (error: any) {
    console.error(`编译失败: ${error.message}`);
    process.exit(1);
  }
}


async function cleanTask(options?: any): Promise<void> {
  // 仅在非静默模式下输出清理开始信息
  if (!options?.silent) {
    // 移除调试日志
  }

  try {

    const compiler = new TMakeCompiler();


    if (compiler.getPluginManager) {
      compiler.getPluginManager().emitEvent(PluginLifecycleEvent.BEFORE_CLEAN);
    }

    const pathsToClean = [
      path.join(process.cwd(), 'dist'),
      path.join(process.cwd(), '.cache'),
      path.join(process.cwd(), 'temp')
    ];

    for (const cleanPath of pathsToClean) {
      if (fs.existsSync(cleanPath)) {
        // 移除了详细的清理路径日志

        function deleteDir(dir: string) {
          const files = fs.readdirSync(dir);
          for (const file of files) {
            const fullPath = path.join(dir, file);
            if (fs.statSync(fullPath).isDirectory()) {
              deleteDir(fullPath);
            } else {
              fs.unlinkSync(fullPath);
            }
          }
          fs.rmdirSync(dir);
        }

        deleteDir(cleanPath);
      }
    }


    if (compiler.getPluginManager) {
      compiler.getPluginManager().emitEvent(PluginLifecycleEvent.AFTER_CLEAN, true);
    }

    // 仅在非静默模式下输出清理完成信息
    if (!options?.silent) {
      // 移除调试日志
    }
  } catch (error: any) {

    try {
      const compiler = new TMakeCompiler();
      if (compiler.getPluginManager) {
        compiler.getPluginManager().emitEvent(PluginLifecycleEvent.AFTER_CLEAN, false);
      }
    } catch (e) {

    }

    console.error(`清理失败: ${error.message}`);
    process.exit(1);
  }
}


async function buildTask(): Promise<void> {
  try {

    const compiler = new TMakeCompiler();
    const pluginManager = compiler.getPluginManager();

    // 加载项目目录下的plugins文件夹中的自定义插件
    const projectPluginsDir = path.join(process.cwd(), 'plugins');
    if (fs.existsSync(projectPluginsDir) && pluginManager) {
      pluginManager.loadPluginsFromDirectory(projectPluginsDir);
    }


    if (pluginManager) {
      pluginManager.emitEvent(PluginLifecycleEvent.BEFORE_BUILD, { args: process.argv.slice(3) });
    }

    await cleanTask();
    await compileTask();


    if (pluginManager) {
      pluginManager.emitEvent(PluginLifecycleEvent.AFTER_BUILD, true);
    }
  } catch (error) {

    try {
      const compiler = new TMakeCompiler();
      if (compiler.getPluginManager) {
        compiler.getPluginManager().emitEvent(PluginLifecycleEvent.AFTER_BUILD, false);
      }
    } catch (e) {

    }

    throw error;
  }
}


async function versionTask(): Promise<void> {
  console.log('TMake 版本: 1.0.0');
}


async function helpTask(): Promise<void> {
  console.log('TMake 使用帮助');
  console.log('================');
  console.log('');
  console.log('任务命令：');
  console.log('  create    - 创建新的结绳项目');
  console.log('  precompile - 预编译.tmake文件到.cache目录');
  console.log('  compile   - 编译结绳项目');
  console.log('  build     - 构建结绳项目（默认命令）');
  console.log('  clean     - 清理构建产物');
  console.log('  help      - 显示帮助信息');
  console.log('  version   - 显示版本信息');
  console.log('');
  console.log('命令行参数：');
  console.log('  --output, -o       - 指定输出目录 (默认: ./dist)');
  console.log('  --package, -p      - 指定包名 (默认: main)');
  console.log('  --platform         - 指定目标平台 (windows/linux/android/macos)');
  console.log('  --debug            - 启用调试模式 (默认: true)');
  console.log('  --release          - 启用发布模式 (覆盖--debug)');
  console.log('  --hard-mode        - 启用严格模式');
  console.log('  --optimize         - 设置优化级别 (0-3)');
  console.log('  --log-level        - 设置日志级别 (debug/info/warning/error)');
  console.log('  --tiecc-dir        - 指定结绳编译器目录');
  console.log('  --config, -c       - 指定配置文件路径');
  console.log('  --watch, -w        - 监视文件变化并自动重新构建');
  console.log('  --help, -h         - 显示帮助信息');
  console.log('  --version, -v      - 显示版本信息');
  console.log('  --generate-functions - 生成函数描述文件 (用于VSCode插件)');
  console.log('');
  console.log('示例：');
  console.log('  tmake build --platform windows --release');
  console.log('  tmake compile -o ./output');
  console.log('  tmake create my-project');
}


function registerTasks(): void {
  taskRegistry.register({
    name: 'create',
    description: '创建新的结绳项目',
    action: createProjectTask
  });

  taskRegistry.register({
    name: 'plugin',
    description: '创建新的TMake插件',
    action: createPluginTask
  });

  taskRegistry.register({
    name: 'precompile',
    description: '预编译.tmake文件到.cache目录',
    action: precompileTask
  });

  taskRegistry.register({
    name: 'compile',
    description: '编译结绳项目',
    action: compileTask
  });

  taskRegistry.register({
    name: 'clean',
    description: '清理构建产物',
    action: cleanTask
  });

  taskRegistry.register({
    name: 'build',
    description: '清理并编译项目',
    action: buildTask
  });

  taskRegistry.register({
    name: 'version',
    description: '显示版本信息',
    action: versionTask
  });

  taskRegistry.register({
    name: 'help',
    description: '显示帮助信息',
    action: helpTask
  });


  taskRegistry.setDefaultTask('compile');
}


async function main(): Promise<void> {
  process.stdout.setEncoding('utf8');
  registerTasks();

  const args = process.argv.slice(2);
  const hasGenerateFunctions = args.includes('--generate-functions') || args.includes('-gf');
  if (hasGenerateFunctions) {
    const fs = require('fs');
    const path = require('path');
    let FunctionDescriptionGenerator, BuildManager;
    try {
      ({ FunctionDescriptionGenerator } = await import('./function-descriptions.js'));
      ({ BuildManager } = await import('./build.js'));
    } catch (err) {
      try {
        const functionDescPath = path.join(__dirname, 'function-descriptions.js');
        const buildPath = path.join(__dirname, 'build.js');
        const functionDescModule = await import(`file://${functionDescPath}`);
        const buildModule = await import(`file://${buildPath}`);
        FunctionDescriptionGenerator = functionDescModule.FunctionDescriptionGenerator;
        BuildManager = buildModule.BuildManager;
      } catch (pkgErr) {
        console.error('加载模块失败:', pkgErr instanceof Error ? pkgErr.message : String(pkgErr));
        process.exit(1);
      }
    }
    
    const buildManager = new BuildManager();
    debugLog('初始化插件...');
    await buildManager.initializePlugins();
    
    // 直接输出到.vscode目录
    const vscodeDir = path.join(process.cwd(), '.vscode');
    const outputPath = path.join(vscodeDir, 'function.json');
    
    // 确保.vscode目录存在
    if (!fs.existsSync(vscodeDir)) {
      try {
        fs.mkdirSync(vscodeDir, { recursive: true });
        debugLog(`已创建.vscode目录: ${vscodeDir}`);
      } catch (err) {
        console.error(`创建.vscode目录失败: ${err instanceof Error ? err.message : String(err)}`);
      }
    }
    
    // 传入pluginManager以获取插件函数信息
    const compiler = buildManager.getCompiler();
    debugLog('生成函数描述...');
    const functions = FunctionDescriptionGenerator.generateFromCompiler(compiler, buildManager.getPluginManager());
    debugLog(`找到 ${functions.length} 个函数`);
    // 打印函数名称列表以便调试
    debugLog('函数列表:');
    functions.forEach((func: any) => debugLog(`- ${func.name} (插件: ${func.plugin || '内置'})`));
    FunctionDescriptionGenerator.writeToFile(functions, outputPath);
    
    debugLog(`函数描述文件已生成到.vscode目录: ${outputPath}`);
    
    console.log('函数描述文件生成完成！');
    process.exit(0);
  }
  
  let taskName = args[0] || taskRegistry.getDefaultTask() || 'help';

  if (taskName === '-h' || taskName === '--help') {
    taskName = 'help';
  } else if (taskName === '-v' || taskName === '--version') {
    taskName = 'version';
  }

  if (taskRegistry.hasTask(taskName)) {
    const task = taskRegistry.getTask(taskName);
    if (task) {
      console.log(`开始执行任务: ${taskName} - ${task.description}`);
      try {
        await task.action();
        console.log(`任务 ${taskName} 执行完成。`);
        process.exit(0);
      } catch (error) {
        console.error(`任务 ${taskName} 执行失败。`);
        process.exit(1);
      }
    }
  } else {
    console.error(`错误: 未知任务 '${taskName}'`);
    process.exit(1);
  }
}
if (require.main === module) {
  main();
}

export { TMakeCompiler, TMakeLexer, TMakeParser };


export { tieBuildPlugin };
